/** 注释
 * @Name hooks;
 * @Author FiveXu
 * @Description hooks
 * @Date 2021-06-25 10:31
 */
import {
  Ref,
  ref,
  onBeforeUnmount,
  watch,
  onBeforeMount,
  getCurrentInstance,
  onMounted,
  onActivated,
  onDeactivated
} from 'vue'
import { ComponentTypes } from '@/base/types'

/** 判断默认插槽下VNode 是否是指定VNode名 通过name属性判定
 * @param {String} slotName
 */
export const useIsDefaultSlotName = (slotName: string): Ref<boolean> => {
  const isButton = ref<boolean>(false)
  const defaultSlots = getCurrentInstance()?.slots
  if (defaultSlots && defaultSlots.default) {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    isButton.value = defaultSlots.default().every((item: any) => item.type?.name === slotName)
  }
  return isButton
}

/** 创建body层文件
 * @param {String} name
 * @param {id|class} tag
 */
export const useCreateTeleport = (name: string, tag: 'id' | 'class' = 'class'): HTMLElement | undefined => {
  const updateIdDom = ref<HTMLElement>()
  const hasId: HTMLElement | null = document.getElementById(name)
  updateIdDom.value = document.createElement('div')
  tag === 'id' ? updateIdDom.value.id = name : updateIdDom.value.className = name
  if (hasId && tag === 'id') updateIdDom.value.id = `${name}-${new Date().getTime()}`
  document.body.append(updateIdDom.value)
  onBeforeUnmount(() => {
    if (updateIdDom.value) document.body.removeChild(updateIdDom.value)
  })
  return updateIdDom.value
}

/** 数据双向绑定 监听数据变换通知双方组件
 * @param props
 * @param value
 */
const modelWatchEmit = ['update:modelValue', 'change']
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useModelWatch = <T>(props: () => T, value: Ref<T>, emitArr: string[] = modelWatchEmit): void => {
  const emit = getCurrentInstance()?.emit
  watch(props, (val: T) => {
    value.value = val
  })
  watch(value, (val: T) => {
    emitArr.forEach((item: string) => {
      emit && emit(item, val)
    })
  })
}

/** 点击空白清空
 * @param {HTMLElement} dom
 * @param {Boolean} show
 */
type UseClickBlankType = Ref<HTMLElement | undefined>
export const useClickBlank = (dom: UseClickBlankType | UseClickBlankType[], show: Ref<boolean>): void => {
  dom = [dom].flat()
  const handleBlankClick = (ev: MouseEvent): void => {
    if (dom instanceof Array) {
      const off = dom.every((item: UseClickBlankType) => item.value && !item.value.contains(ev.target as Node))
      if (off) show.value = false
    }
  }
  onBeforeMount(() => {
    document.addEventListener('mousedown', handleBlankClick, true)
  })
  onBeforeUnmount(() => {
    document.removeEventListener('mousedown', handleBlankClick, true)
  })
}

/** 设置弹窗位置
 * @param parentDom
 * @param dropdownDom
 * @param show
 */
export const setDropdownPosition = (parentDom: Ref<HTMLElement | undefined>, dropdownDom: Ref<HTMLElement | undefined>, show: Ref<boolean>): void => {
  if (!parentDom.value || !dropdownDom.value) return
  const rect = parentDom.value.getBoundingClientRect()
  const { height: contentHeight } = dropdownDom.value.getBoundingClientRect()
  const { clientHeight } = document.body
  dropdownDom.value.style.width = `${rect.width}px`
  dropdownDom.value.style.left = `${rect.left}px`
  dropdownDom.value.style.top = `${rect.top + rect.height}px`
  if ((rect.top + rect.height + contentHeight + 20) >= clientHeight) {
    show.value = true
    dropdownDom.value.style.top = `${rect.top - contentHeight}px`
  } else {
    show.value = false
  }
}

/** 返回对应主图颜色
 * @param type
 */
export const useThemeColor = (type: ComponentTypes): string => {
  switch (type) {
    case 'primary':
      return 'rgb(45, 183, 245)'
    case 'success':
      return 'rgb(103, 194, 58)'
    case 'warning':
      return 'rgb(255, 153, 0)'
    case 'error':
      return 'rgb(237, 60, 20)'
    default:
      return 'rgb(45, 183, 245)'
  }
}

/** 获取不同单位下的真实px值
 * @param size 带单位数值
 * @param defaultSize 默认值 当size异常时 备用
 * @param widthOrHeight 宽高 确定%数下 选择宽高做比值
 */
export const getSize = (size: string, defaultSize: number, widthOrHeight: 'width' | 'height' = 'width'): number => {
  const winW = document.documentElement.clientWidth
  const winH = document.documentElement.clientHeight
  if (!Number.isNaN(Number(size))) {
    return Number(size)
  } else if (size.includes('px')) {
    return Number(size.replace(/px/g, ''))
  } else if (size.includes('%')) {
    const count = Number(size.replace(/%/g, ''))
    if (widthOrHeight === 'width') return count * winW / 100
    if (widthOrHeight === 'height') return count * winH / 100
  } else if (size.includes('vw')) {
    const count = Number(size.replace(/vw/g, ''))
    return count * winW / 100
  } else if (size.includes('vh')) {
    const count = Number(size.replace(/vh/g, ''))
    return count * winH / 100
  }
  return defaultSize
}

/** 页面进入时触发
 * @param cb
 */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useCheckinPage = (cb: () => void) => {
  onMounted(cb)
  onActivated(cb)
}

/** 页面退出时触发
 * @param cb
 */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useCheckoutPage = (cb: () => void) => {
  onBeforeUnmount(cb)
  onDeactivated(cb)
}

/** setInterval 定时器
 * @param cb 事件回调
 * @param delay 定时时间
 */
export const useSetInterval = (cb: () => void, delay: number): () => void => {
  delay = Number.isNaN(Number(delay)) ? 20 : Number(delay)
  let timer: null | ReturnType<typeof setTimeout> = null
  let clear = false
  const interval = () => {
    if (clear) {
      timer && clearTimeout(timer)
      return
    }
    cb()
    timer && clearTimeout(timer)
    timer = setTimeout(interval, Math.abs(delay))
  }
  interval()
  return () => {
    clear = true
  }
}

let zIndex = 2000
export const getZIndex = (): number => zIndex++
